package se.sll.service.catalogue.common.auth;

import de.rtner.security.auth.spi.SaltedDatabaseServerLoginModule;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.sql.DataSource;
import javax.transaction.SystemException;
import javax.transaction.Transaction;

/**
 * JBoss database server login module that provides "last login" capability
 * and salted passwords through SaltedDatabaseServerLoginModule.
 * 
 * @author Christer Palm, Nogui
 */
public class ServiceCatalogueLoginModule extends SaltedDatabaseServerLoginModule {
    protected String loginUpdate;

    @Override
    public void initialize(Subject subject, CallbackHandler callbackHandler,
            Map<String, ?> sharedState, Map<String, ?> options)
    {
        super.initialize(subject, callbackHandler, sharedState, options);

        Object tmp = options.get("loginUpdate");
        if (tmp != null) {
            loginUpdate = tmp.toString();
        }
    }

    @Override
    public boolean login() throws LoginException {
        boolean successfulLogin = super.login();
        if (successfulLogin && loginUpdate != null) {
            Transaction tx = null;
            if (suspendResume) {
                tx = suspendTransaction();
            }
            Connection conn = null;
            PreparedStatement ps = null;
            try {
                InitialContext ctx = new InitialContext();
                DataSource ds = (DataSource) ctx.lookup(dsJndiName);
                conn = ds.getConnection();
                String username = getUsername();
                if (trace) {
                    log.trace("Executing update: " + loginUpdate + ", with username: " + username);
                }
                ps = conn.prepareStatement(loginUpdate);
                ps.setString(1, username);
                ps.executeUpdate();
            } catch (NamingException ex) {
                LoginException le = new LoginException("Error looking up DataSource from: " + dsJndiName);
                le.initCause(ex);
                throw le;
            } catch (SQLException ex) {
                LoginException le = new LoginException("Update failed");
                le.initCause(ex);
                throw le;
            } finally {
                close(ps);
                close(conn);
                if (suspendResume) {
                    resumeTransaction(tx);
                }
            }
        }
        return successfulLogin;
    }

    private Transaction suspendTransaction() {
        Transaction tx;
        try {
            if (tm == null) {
                throw new IllegalStateException("Transaction Manager is null");
            }
            tx = tm.suspend();
        } catch (SystemException e) {
            throw new RuntimeException(e);
        }
        if (trace) {
            log.trace("suspendAnyTransaction");
        }
        return tx;
    }

    private void resumeTransaction(Transaction tx) {
        //TransactionDemarcationSupport.resumeAnyTransaction(tx);
        try {
            tm.resume(tx);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (log.isTraceEnabled()) {
            log.trace("resumeAnyTransaction");
        }
    }

    private void close(ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
            }
        }
    }

    private void close(PreparedStatement ps) {
        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
            }
        }
    }

    private void close(Connection conn) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException ex) {
            }
        }
    }
}
